<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>气象数据可视化平台</title>
    <!-- 引入ECharts CDN -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    <!-- 引入jQuery（简化AJAX请求） -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js"></script>
    <!-- 引入Element UI（简化时间选择器，可选） -->
    <!--<script src="https://cdn.tailwindcss.com"></script>-->
    <style>

        /* ========== 1. 标题（h4）：更大更突出 ========== */
        .stat-item h4 {
            font-size: 18px !important; /* 原16px → 调大到18px（!important 确保覆盖Tailwind） */
            font-weight: 700 !important;/* 加粗更醒目（可选，原600→700） */
            margin-bottom: 12px !important; /* 与数值间距调大 */
        }

        /* ========== 2. 数值（.text-3xl.font-bold）：大幅放大 ========== */
        .stat-item .text-3xl.font-bold {
            font-size: 40px !important; /* 原~30px（Tailwind text-3xl是1.875rem≈30px）→ 调大到40px */
            font-weight: 800 !important;/* 加粗升级（原700→800，更厚重） */
            margin-bottom: 8px !important; /* 与单位间距调大 */
        }

        /* ========== 3. 单位（.text-sm）：同步放大 ========== */
        .stat-item .text-sm {
            font-size: 16px !important; /* 原~14px（Tailwind text-sm是0.875rem≈14px）→ 调大到16px */
            font-weight: 500 !important;/* 轻微加粗，让单位更清晰（可选） */
        }

        /* ========== 4. 可选：卡片内边距适配大字体 ========== */
        .stat-item {
            padding: 32px !important; /* 原24px → 调大到32px，避免大字体溢出 */
        }
        /* ========== 1. 父容器布局：让卡片分开 ========== */
        /* 假设父容器是 .stats-card（如果没有，给外层加这个类） */
        .stats-card {
            display: grid;               /* 网格布局 */
            grid-template-columns: repeat(3, 1fr); /* 3列均分 */
            gap: 20px;                   /* 卡片之间的间距（关键！拉开距离） */
            margin: 20px 0;              /* 与上下模块的间距 */
        }

        /* ========== 2. 单个卡片样式：独立 + 立体 ========== */
        .stat-item {
            padding: 24px;               /* 内部留白，更舒展 */
            border-radius: 12px;         /* 圆角更明显 */
            box-shadow: 0 4px 12px rgba(0,0,0,0.05); /* 阴影增强层次感 */
            transition: all 0.3s ease;   /* 悬停动画过渡 */
        }

        /* 悬停特效：轻微上浮 + 阴影加深（交互更生动） */
        .stat-item:hover {
            transform: translateY(-2px); /* 上移一点 */
            box-shadow: 0 6px 16px rgba(0,0,0,0.1); /* 阴影更突出 */
        }

        /* 背景色保持原有类（和后端一致） */
        .stat-item.blue { background-color: #e6f3ff; }  /* 浅蓝 */
        .stat-item.green { background-color: #e6ffe6; } /* 浅绿 */
        .stat-item.yellow { background-color: #fff9e6; }/* 浅黄 */

        /* ========== 3. 文字样式：标题、数值、单位分层 ========== */
        /* 标题：h4 */
        .stat-item h4 {
            font-size: 16px;             /* 标题大小适中 */
            font-weight: 600;            /* 标题加粗 */
            color: #333;                 /* 标题颜色沉稳 */
            margin-bottom: 8px;          /* 与数值拉开距离 */
        }

        /* 数值：.text-3xl.font-bold（保留原有 Tailwind 类，覆盖样式） */
        .stat-item .text-3xl.font-bold {
            font-size: 28px;             /* 数值更大更醒目 */
            font-weight: 700;            /* 数值更粗 */
            color: #111;                 /* 数值颜色更重 */
            margin-bottom: 4px;          /* 与单位拉开距离 */
        }

        /* 单位：.text-sm（保留原有 Tailwind 类，覆盖样式） */
        .stat-item .text-sm {
            font-size: 14px;             /* 单位稍小 */
            color: #666;                 /* 单位颜色弱化，不抢戏 */
        }



        .query-card {
            padding: 16px;
        }
        .query-bar {
            display: flex;
            align-items: center;
            gap: 15px; /* 元素间距 */
        }

        /* 图表卡片：内边距 */
        .chart-card {
            padding: 20px;
        }

        /* 统计面板：网格布局（替代Tailwind的grid） */
        .stats-card {
            display: grid;
            grid-template-columns: repeat(3, 1fr); /* 3列均分 */
            gap: 20px; /* 列间距 */
            margin: 20px 0;
        }

        /* 统计项：背景色和内边距 */
        .stat-item {
            padding: 16px;
            border-radius: 8px;
        }
        .stat-item.blue { background-color: #e6f3ff; } /* 浅蓝色 */
        .stat-item.green { background-color: #e6ffe6; } /* 浅绿色 */
        .stat-item.yellow { background-color: #fff9e6; } /* 浅黄色 */

        /* 时间输入框优化 */
        .time-input {
            padding: 8px 12px;
            border: 1px solid #e5e7eb; /* 浅灰色边框 */
            border-radius: 4px;
            width: 200px;
        }

        /* 按钮优化（悬停透明度变化） */
        .query-btn {
            padding: 8px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: opacity 0.3s ease;
        }
        .query-btn:hover {
            opacity: 0.9; /* 悬停变透明 */
        }

        /* 图表容器高度 */
        .chart-container {
            width: 100%;
            height: 500px;
        }
        /* 通用卡片样式 */
        .card {
            background-color: #fff;        /* 白色背景 */
            border-radius: 8px;            /* 圆角 */
            box-shadow: 0 4px 12px rgba(0,0,0,0.05); /* 初始阴影 */
            transition: all 0.3s ease;     /* 过渡动画 */
        }
        /* 悬停特效：上移+阴影加深 */
        .card:hover {
            transform: translateY(-2px);   /* 轻微上移 */
            box-shadow: 0 6px 16px rgba(0,0,0,0.1); /* 更明显的阴影 */
        }
        .container {
            width: 90%;
            margin: 20px auto;
        }
        .chart-card {
            margin-bottom: 30px;
            padding: 20px;
            border: 1px solid #eee;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.05);
        }
        .query-bar {
            margin-bottom: 20px;
            display: flex;
            gap: 15px;
            align-items: center;
        }
        .time-input {
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
            width: 200px;
        }
        .query-btn {
            padding: 8px 20px;
            background: #409EFF;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

    </style>
</head>
<body>
<div class="container">
    <!-- 查询栏：时间范围选择 -->
    <div class="card query-card p-4 mb-4">
        <div class="query-bar">
            <input type="datetime-local" id="startTime" class="time-input" value="2024-10-09T00:00">
            <span>至</span>
            <input type="datetime-local" id="endTime" class="time-input" value="2024-10-10T23:00">
            <button class="query-btn" onclick="loadAllCharts()">查询数据</button>
            <button class="query-btn" style="background:#67C23A" onclick="startRealTimeRefresh()">开启实时刷新</button>
            <button class="query-btn" style="background:#F56C6C" onclick="stopRealTimeRefresh()">停止实时刷新</button>
        </div>
    </div>
    <!-- 1. 气候趋势折线图 -->
    <div class="card chart-card p-4 mb-4">
        <h3>气候趋势监测（2米气温/湿度/10米风速）</h3>
        <div id="trendChart" class="chart-container"></div>
    </div>

    <!-- 天级数据统计面板 -->
    <div class=" stats-card ">
        <div class="stat-item blue">
            <h4>平均气温</h4>
            <p id="avgTemp" class="text-3xl font-bold">--</p>
            <p class="text-sm">℃</p>
        </div>
        <div class="stat-item green">
            <h4>总降水量</h4>
            <p id="totalPrecip" class="text-3xl font-bold">--</p>
            <p class="text-sm">mm</p>
        </div>
        <div class="stat-item yellow">
            <h4>最大风速</h4>
            <p id="maxWind" class="text-3xl font-bold">--</p>
            <p class="text-sm">m/s</p>
        </div>
    </div>

    <!-- 1. 日最高/最低气温折线图 -->
    <div class="card chart-card p-4 mb-4">
        <h3>日最高/最低气温变化</h3>
        <div id="dailyTempChart" class="chart-container"></div>
    </div>

    <!-- 2. 日降水量柱状图 -->
    <div class="card chart-card p-4 mb-4">
        <h3>日降水量分布</h3>
        <div id="dailyPrecipChart" class="chart-container"></div>
    </div>

    <!-- 3. 日最大风速折线图 -->
    <div class="card chart-card p-4 mb-4">
        <h3>日最大风速变化</h3>
        <div id="dailyWindChart" class="chart-container"></div>
    </div>
    <!-- 替换原“7天出行建议”的列表，改为图表 -->
    <div class="card chart-card p-4 mb-4" id="travelAdviceChartCard">
        <h3>未来出行建议可视化</h3>
        <div id="travelAdviceChart" class="chart-container"></div>
    </div>
</div>
<script>
    // 初始化折线图和热力图实例
    let trendChart = echarts.init(document.getElementById('trendChart'));
    //let heatChart = echarts.init(document.getElementById('heatChart'));
    let refreshInterval = null; // 实时刷新定时器

    // 初始化天级图表实例
    let dailyTempChart = echarts.init(document.getElementById('dailyTempChart'));
    let dailyPrecipChart = echarts.init(document.getElementById('dailyPrecipChart'));
    let dailyWindChart = echarts.init(document.getElementById('dailyWindChart'));


    function loadAllCharts() {
        loadTrendChart();  // 原有小时级折线图
       // loadHeatChart();   // 原有热力图（可保留或移除，此处保留）
        loadDailyCharts(); // 新增天级图表
        loadTravelAdvice();
    }

    // 新增：加载天级数据
    function loadDailyCharts() {
        // 提取日期部分（从 datetime-local 中截取）
        const startDate = document.getElementById('startTime').value.split('T')[0];
        const endDate = document.getElementById('endTime').value.split('T')[0];

        $.get("/api/weather/daily", { startDate, endDate }, (res) => {
            // 更新统计面板
            document.getElementById('avgTemp').innerText = res.avgTemperature.toFixed(1);
            document.getElementById('totalPrecip').innerText = res.totalPrecipitation.toFixed(2);
            document.getElementById('maxWind').innerText = res.maxWindSpeed.toFixed(1);

            // 1. 日最高/最低气温折线图
            dailyTempChart.setOption({
                // 新增 tooltip 配置
                tooltip: {
                    trigger: 'axis', // 触发方式：鼠标 hover 到坐标轴时，显示该位置所有系列的数据
                    formatter: function(params) {
                        // params 是当前 hover 位置的所有系列数据（数组）
                        let html = `${params[0].axisValue}<br>`; // 显示 x 轴的日期/时间
                        params.forEach((item) => {
                            // 拼接系列名称和数值（比如“最高气温: 30℃”）
                            html += `${item.seriesName}: ${item.value}℃<br>`;
                        });
                        return html;
                    }
                },
                xAxis: { type: 'category', data: res.xaxis },
                yAxis: { type: 'value', name: '气温(℃)' },
                series: [
                    { name: '最高气温', type: 'line', data: res.tempMaxData, color: '#FF4500' },
                    { name: '最低气温', type: 'line', data: res.tempMinData, color: '#1E90FF' }
                ]
            });

            // 2. 日降水量柱状图
            dailyPrecipChart.setOption({
                // 新增 tooltip 配置
                tooltip: {
                    trigger: 'axis', // 触发方式：鼠标 hover 到坐标轴时，显示该位置所有系列的数据
                    formatter: function(params) {
                        // params 是当前 hover 位置的所有系列数据（数组）
                        let html = `${params[0].axisValue}<br>`; // 显示 x 轴的日期/时间
                        params.forEach((item) => {
                            // 拼接系列名称和数值（比如“最高气温: 30℃”）
                            html += `${item.seriesName}: ${item.value}℃<br>`;
                        });
                        return html;
                    }
                },
                xAxis: { type: 'category', data: res.xaxis },
                yAxis: { type: 'value', name: '降水量(mm)' },
                series: [{ name: '日降水量', type: 'bar', data: res.precipitationData, color: '#4169E1' }]
            });

            // 3. 日最大风速折线图
            dailyWindChart.setOption({
                // 新增 tooltip 配置
                tooltip: {
                    trigger: 'axis', // 触发方式：鼠标 hover 到坐标轴时，显示该位置所有系列的数据
                    formatter: function(params) {
                        // params 是当前 hover 位置的所有系列数据（数组）
                        let html = `${params[0].axisValue}<br>`; // 显示 x 轴的日期/时间
                        params.forEach((item) => {
                            // 拼接系列名称和数值（比如“最高气温: 30℃”）
                            html += `${item.seriesName}: ${item.value}℃<br>`;
                        });
                        return html;
                    }
                },
                xAxis: { type: 'category', data: res.xaxis },
                yAxis: { type: 'value', name: '风速(m/s)' },
                series: [{ name: '最大风速', type: 'line', data: res.windSpeedData, color: '#32CD32' }]
            });
        });
    }




















    // 2. 加载气候趋势折线图
    function loadTrendChart() {
        const startTime = document.getElementById('startTime').value;
        const endTime = document.getElementById('endTime').value;
        const hourInterval = 2; // 需根据实际数据间隔修改（核心参数）

        $.get("/api/weather/chart/trend", { startTime, endTime }, (res) => {
            const option = {
                title: { text: '小时级气象趋势', left: 'center' },
                tooltip: { trigger: 'axis' },
                legend: { data: ['2米气温(℃)', '2米相对湿度(%)', '10米风速(m/s)'], top: 30 },
                grid: {
                    left: '8%',    // 原3% → 增大左侧边距（容纳Y轴标签）
                    right: '12%',  // 原4% → 增大右侧边距（容纳图例/右侧Y轴）
                    top: '15%',    // 新增顶部边距（避免标题与图例重叠）
                    bottom: '10%', // 原3% → 增大底部边距（容纳X轴标签/滑动条）
                    containLabel: true // 强制标签在grid内，避免溢出
                },
                xAxis: {
                    type: 'category',
                    data: res.xaxis,
                    axisLabel: {
                        // 只显示间隔为 hourInterval 的索引对应的标签（每隔1小时）
                        formatter: function(value, index) {
                            // 索引能被 hourInterval 整除时显示标签，否则隐藏（返回空字符串）
                            if (index % hourInterval === 0) {
                                // 可简化显示格式（例如只保留小时:分钟）
                                return value//.split(' ')[1] || value; // 假设时间格式是 "日期 时间"，取后半部分
                            } else {
                                return ''; // 隐藏非目标标签
                            }
                        },
                        //interval: 0,          // 强制显示所有标签（配合旋转）
                        rotate: 0,          // 旋转45度
                        margin: 10           // 标签与轴的间距
                    },
                    boundaryGap: false
                },
                yAxis: [
                    {
                        type: 'value',
                        name: '气温(℃)',
                        min: -10,
                        max: 30
                    },
                    {
                        type: 'value',
                        name: '湿度(%) / 风速(m/s)', // 合并右侧轴名称
                        min: 0,
                        max: 100, // 后续可改为 `dataMin/dataMax` 动态适配
                        position: 'right'
                    }
                ],
                dataZoom: [
                    {
                        type: 'slider',      // 底部滑动条
                        xAxisIndex: 0,       // 绑定X轴
                        start: 10, end: 90,  // 初始显示10%-90%数据（避免全缩）
                        height: 20,          // 滑动条高度
                        handleSize: 10       // 滑块大小
                    },
                    {
                        type: 'inside',      // 鼠标滚轮缩放
                        xAxisIndex: 0
                    }
                ],
                series: [
                    {
                        name: '2米气温(℃)',
                        type: 'line',
                        data: res.temperatureData,
                        itemStyle: { color: '#FF4500' },
                        yAxisIndex: 0, // 关联左轴
                        sampling: 'lttb'
                    },
                    {
                        name: '2米相对湿度(%)',
                        type: 'line',
                        data: res.humidityData,
                        itemStyle: { color: '#1E90FF' },
                        yAxisIndex: 1, // 关联右轴
                        sampling: 'lttb'
                    },
                    {
                        name: '10米风速(m/s)',
                        type: 'line',
                        data: res.windSpeedData,
                        itemStyle: { color: '#32CD32' },
                        yAxisIndex: 1, // 关联右轴（与湿度共享）
                        sampling: 'lttb'
                    }
                ]
            };
            trendChart.setOption(option);
        });
    }

    // 辅助函数：通过权重反向获取天气代码（与后端权重规则对应）
    function getCodeByWeight(weight, codeMap) {
        const weightCodeMap = {
            1: 45,   // 雾
            2: 48,   // 冻雾（或95雷雨）
            3: 65,   // 大雨（或75/82/86）
            4: 67,   // 重度冻雨
            5: 96    // 雷雨+冰雹
        };
        return weightCodeMap[weight] || '';
    }
    // 4. 开启实时刷新（每30秒更新一次）
    function startRealTimeRefresh() {
        if (refreshInterval) clearInterval(refreshInterval);
        refreshInterval = setInterval(() => {
            loadAllCharts();
            loadTravelAdvice(); // 新增：实时刷新建议
        }, 30000);
        alert("已开启实时刷新（每30秒更新）");
    }

    // 5. 停止实时刷新
    function stopRealTimeRefresh() {
        if (refreshInterval) {
            clearInterval(refreshInterval);
            refreshInterval = null;
            alert("已停止实时刷新");
        }
    }
    // 修复：支持负数 + 清理干扰字符
    function parseTemp(tempStr) {
        // 1. 清理非数字和负号的字符（如“高温 ”、“℃”、全角空格）
        const cleaned = tempStr.replace(/[^\d\-]/g, '').trim();
        // 2. 匹配正负数字（如“-5”、“10”）
        const match = cleaned.match(/-?\d+/);
        return match ? parseFloat(match[0]) : 0;
    }
    // 从建议文本中解析风险等级（1:低, 2:中, 3:高）
    function parseRiskLevel(advice) {
        // 高风险关键词（严重隐患、强制措施）
        const highRisk = ['严重', '事故隐患', '停止体力消耗', '避免户外活动'];
        // 中风险关键词（一般隐患、建议措施）
        const mediumRisk = ['注意', '一般隐患', '减少外出', '佩戴口罩'];

        // 优先判断高风险
        for (let word of highRisk) {
            if (advice.includes(word)) return 3;
        }
        // 再判断中风险
        for (let word of mediumRisk) {
            if (advice.includes(word)) return 2;
        }
        // 默认低风险
        return 1;
    }
    // 新增：加载7天出行建议
    function loadTravelAdvice() {
        const startTime = document.getElementById('startTime').value;
        const endTime = document.getElementById('endTime').value;

        $.get("/api/travel/advice", { startTime, endTime }, (res) => {
            // 定位到正确的数据路径：res.data.data.forecast
            const forecasts = res.data?.data?.forecast || [];
            if (forecasts.length === 0) {
                alert("未获取到7天出行建议数据");
                return;
            }

            const xAxisData = [];        // 日期+星期（如：2025-11-05 星期三）
            const tempMaxData = [];      // 最高温度（数值）
            const tempMinData = [];      // 最低温度（数值）
            const riskData = [];         // 风险等级（1-3）
            const tooltipMeta = [];      // 存储天气类型、完整建议

            forecasts.forEach((item) => {
                const ymd = item.ymd;
                const week = item.week;
                const highTemp = parseTemp(item.high);
                const lowTemp = parseTemp(item.low);
                const advice = item.formalAdvice;
                const weatherType = item.type;

                xAxisData.push(`${ymd}（${week}）`);
                tempMaxData.push(highTemp);
                tempMinData.push(lowTemp);
                riskData.push(parseRiskLevel(advice));
                tooltipMeta.push({ type: weatherType, advice });
            });

            // 初始化ECharts实例
            const adviceChart = echarts.init(document.getElementById('travelAdviceChart'));

            // ECharts配置项
            const option = {
                title: { text: '未来两周出行建议可视化' },
                tooltip: {
                    trigger: 'axis',
                    axisPointer: { type: 'cross' },
                    formatter: (params) => {
                        const index = params[0].dataIndex;
                        const dateWeek = xAxisData[index];
                        const weather = tooltipMeta[index].type;
                        const advice = tooltipMeta[index].advice;
                        const tempMin = tempMinData[index];
                        const tempMax = tempMaxData[index];
                        const riskText = riskData[index] === 1 ? '低风险'
                            : riskData[index] === 2 ? '中风险' : '高风险';

                        // 替换换行符为<br>，优化显示
                        return `
                        日期：${dateWeek}<br>
                        天气：${weather}<br>
                        温度：${tempMin}~${tempMax}℃<br>
                        风险等级：${riskText}<br>
                        建议：${advice.replace(/\n/g, '<br>')}
                    `;
                    }
                },
                xAxis: {
                    type: 'category',
                    data: xAxisData,
                    axisLabel: { rotate: 45, margin: 15 } // 旋转日期，避免重叠
                },
                yAxis: [
                    {
                        type: 'value',
                        name: '温度(℃)',
                        min: 'dataMin', // 自动适配最小值
                        max: 'dataMax', // 自动适配最大值
                        axisLabel: { formatter: '{value}℃' }
                    },
                    {
                        type: 'value',
                        name: '风险等级',
                        min: 0,
                        max: 3,
                        axisLabel: {
                            formatter: (val) => val === 1 ? '低' : val === 2 ? '中' : '高'
                        },
                        position: 'right'
                    }
                ],
                series: [
                    {
                        name: '最高温度',
                        type: 'line',
                        data: tempMaxData,
                        yAxisIndex: 0,
                        itemStyle: { color: '#FF4500' },
                        // 关键修正：用函数动态获取值
                        label: {
                            show: true,
                            position: 'top',
                            formatter: (params) => `${params.value}℃`
                        }
                    },
                    {
                        name: '最低温度',
                        type: 'line',
                        data: tempMinData,
                        yAxisIndex: 0,
                        itemStyle: { color: '#1E90FF' },
                        label: {
                            show: true,
                            position: 'bottom',
                            formatter: (params) => `${params.value}℃`
                        }
                    },
                    {
                        name: '风险等级',
                        type: 'scatter',
                        data: riskData,
                        yAxisIndex: 1,
                        symbolSize: 20,
                        itemStyle: {
                            color: (val) => val.data === 1 ? '#67C23A'
                                : val.data === 2 ? '#E6A23C' : '#F56C6C'
                        },
                        label: {
                            show: true,
                            formatter: (val) => val.data === 1 ? '低' : val.data === 2 ? '中' : '高',
                            color: '#fff',
                            position: 'inside'
                        }
                    }
                ]
            };

            adviceChart.setOption(option);
        });
    }

    // 辅助函数：从建议文本中提取风险等级（HIGH→3，MEDIUM→2，LOW→1）
    function parseRiskLevel(advice) {
        if (advice.includes('HIGH')) return 3;
        if (advice.includes('MEDIUM')) return 2;
        return 1; // 默认为LOW
    }
    // 6. 窗口大小变化时，自适应图表
    window.addEventListener('resize', () => {
        trendChart.resize();
        //heatChart.resize();
        const adviceChart = echarts.getInstanceByDom(document.getElementById('travelAdviceChart'));
        if (adviceChart) {
            adviceChart.resize();
        }
    });

    // 初始加载图表
    window.onload = () => {
        loadAllCharts();
        loadTravelAdvice(); // 新增：加载出行建议
    };

</script>
</body>
</html>
